using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using System;
using System.Collections.Generic;
using System.Text;

namespace IQIGame.Onigao.Logic
{
    /// <summary>
    /// 所有entity eo的基类
    /// </summary>
    /// <typeparam name="POD"></typeparam>
    public abstract class BaseEntity : BaseLevelFunctionHost, IBehaviourSubject, IFixedQuadTreeObject, IFixedBVHObject2D, ICFSMEntity
    {
        public int id { get; protected set; }

        /// <summary>
        /// 地区EO
        /// </summary>
        public Vector3Logic position { get; protected set; }
        /// <summary>
        /// 是否激活
        /// </summary>
        public bool isActive { get; protected set; }
        /// <summary>
        /// 是否有效实体
        /// </summary>
        public bool isAvailable => !isRemoved && isActive;
        /// <summary>
        /// 行为树是否激活
        /// </summary>
        public virtual bool isBehavTreeActive => isAvailable;
        public virtual bool isFsmAvailable => isAvailable;
        public Vector3Logic dir => dirUnnormalized == Vector3Logic.zero ? Vector3Logic.forward : dirUnnormalized.normalized;
        public Vector3Logic dirUnnormalized { get; set; }
        /// <summary>
        /// 四叉树位置（接口方法）
        /// </summary>
        public Vector2Logic quadTreePos { get; set; }
        /// <summary>
        /// BVH树位置（接口方法）
        /// </summary>
        public FixedBVHBounds2D bvhBounds { get; set; }
        /// <summary>
        /// 行为树代理类（接口方法）
        /// </summary>
        public IBehaviourAgent agent { get; set; }
        /// <summary>
        /// 是否被占用（有状态）
        /// </summary>
        public bool isOccupied => _occupationStatus != null && _occupationStatus.Count > 0;
        /// <summary>
        /// 静态阻挡或动态避障的id，由Recast寻路底层管理。
        /// </summary>
        public uint ObstacleId { get; set; }
        /// <summary>
        /// 寻路代理，自动寻路时使用
        /// </summary>
        public LgLevelNavigator navigator
        {
            get
            {
                if (_navigator == null)
                {
                    _navigator = AddComponent<LgLevelNavigator>();
                }
                return _navigator;
            }
        }
        /// <summary>
        /// 是否被移除
        /// </summary>
        public bool isRemoved { get; set; }
        /// <summary>
        /// 行为树名
        /// </summary>
        public string behaviourName { get; protected set; }
        /// <summary>
        /// 状态机名
        /// </summary>
        public string stateMachineName { get; protected set; }
        public int defaultMoveSpeed { get; protected set; }
        public float buffSpeedRatio => _buffManager == null ? 1 : _buffManager.CalcSpeedRatio();
        /// <summary>
        /// 移动速度，cm/s
        /// </summary>
        public int moveSpeed => (int)(defaultMoveSpeed * buffSpeedRatio);
        /// <summary>
        /// 是否是寻路网格Agent（需要动态避障）
        /// </summary>
        protected abstract bool isNavAgent { get; }
        public override LevelRegion region => _region;

        /// <summary>
        /// 导航控制器
        /// </summary>
        protected LgLevelNavigator _navigator;
        /// <summary>
        /// 占用英雄的实体（正在与当前实体交互）
        /// </summary>
        protected Dictionary<EntityOccupationStatus, BaseEntity> _interactingEntityMap;
        protected Dictionary<EntityDynamicPropertyType, IEntityDynamicProperty> _dynamicProps;

        /// <summary>
        /// 有状态行为的占用状态
        /// </summary>
        private Dictionary<EntityOccupationStatus, int> _occupationStatus;
        /// <summary>
        /// 有状态行为的占用状态
        /// </summary>
        private Dictionary<EntityOccupationStatus, object> _occupationStatusObj;
        /// <summary>
        /// 所有的组件
        /// </summary>
        private Dictionary<Type, LogicBaseEntityComponent> _components = new Dictionary<Type, LogicBaseEntityComponent>();
        private List<LogicBaseEntityComponent> _tempComponents = new List<LogicBaseEntityComponent>();
        protected LevelRegion _region;
        /// <summary>
        /// 行为是否暂停
        /// </summary>
        protected bool _isSystemPauseBehav;

        protected void InnerInit(int id, LevelRegion region, Vector3Int position, bool isActive, Vector3Int initDirEuler)
        {
            this.id = id;
            this._region = region;
            this.position = position;
            this.isActive = isActive;
            this.dirUnnormalized = Vector3Logic.EulerXyToDirection(initDirEuler);
            defaultMoveSpeed = LgLevelConst.EntitySpeed;
        }

        public virtual void LogicOnUpdate()
        {
            if (!isAvailable)
            {
                return;
            }
            if (_components.Count > 0)
            {
                try
                {
                    foreach (var kv in _components) //防止执行过程中移除Component出错
                    {
                        _tempComponents.Add(kv.Value);
                    }
                    foreach (LogicBaseEntityComponent component in _tempComponents)
                    {
                        if (!component.isReleased) //防止当前Component被其他Component移除后继续执行
                        {
                            component.LogicOnUpdate();
                        }
                    }
                }
                catch (Exception e)
                {
                    LogicLog.LogException(e);
                }
                finally
                {
                    _tempComponents.Clear();
                }
            }
            _buffManager?.LogicOnUpdate();
        }

        public T AddComponent<T>() where T : LogicBaseEntityComponent, new()
        {
            T t = ClassPool.Get<T>();
            t.OnInit(this);
            if (!_components.TryAdd(typeof(T), t))
            {
                LogicLog.LogError("不允许重复添加组件：" + typeof(T).Name);
            }
            return t;
        }

        public void RemoveComponent<T>() where T : LogicBaseEntityComponent
        {
            Type t = typeof(T);
            if (_components.Remove(t, out var component))
            {
                ClassPool.PutAutoType(component);
            }

            if (t == typeof(LgLevelNavigator))
            {
                _navigator = null;
            }
        }

        public T GetComponent<T>() where T : LogicBaseEntityComponent
        {
            if (_components.TryGetValue(typeof(T), out var component))
            {
                return (T)component;
            }
            return null;
        }

        public void GetInterruptibleComponents(List<IInterruptibleComponent> result)
        {
            foreach (var kv in _components)
            {
                var component = kv.Value;
                if (component is IInterruptibleComponent)
                {
                    result.Add((IInterruptibleComponent)component);
                }
            }
        }

        public virtual bool SetActive(bool isActive)
        {
            if (this.isActive == isActive)
            {
                return false;
            }
            this.isActive = isActive;
            return true;
        }

        /// <summary>
        /// 在寻路网格中移动
        /// </summary>
        /// <param name="targetPoint"></param>
        /// <param name="speedRatio"></param>
        /// <param name="needSync"></param>
        /// <param name="dirType"></param>
        /// <returns></returns>
        public virtual bool MoveInNavMesh(Vector3Logic targetPoint, float speedRatio, bool needSync, EntityMoveDirType dirType = EntityMoveDirType.KeepVertical)
        {
            bool success = false;
            if (region.terrain.TryMove(position, targetPoint, out var validRealPos))
            {
                //需要动态避障
                if (isNavAgent)
                {
                    if (region.terrain.SetAgentPos(ObstacleId, validRealPos))
                    {
                        success = true;
                    }
                }
                else
                {
                    success = true;
                }
            }
            if (success)
            {
                UpdateMove(validRealPos, speedRatio, needSync, dirType);
            }
            return success;
        }

        /// <summary>
        /// 在寻路网格中传送
        /// </summary>
        /// <param name="useAgentMove"></param>
        /// <param name="targetPoint"></param>
        /// <returns></returns>
        protected virtual bool TeleportInNavMesh(bool useAgentMove, Vector3Logic targetPoint)
        {
            bool success = false;
            int errorCode = 1;
            if (region.terrain.FindNearestPoint(targetPoint, out var validRealPos))
            {
                errorCode = 2;
                if (useAgentMove)
                {
                    if (region.terrain.SetAgentPos(ObstacleId, validRealPos))
                    {
                        success = true;
                        errorCode = 0;
                    }
                }
                else
                {
                    success = true;
                    errorCode = 0;
                }
            }

            if (success)
            {
                UpdateMove(validRealPos, 1, false, EntityMoveDirType.KeepRotation);
                LogicLog.Log("传送成功，需求目标点：" + targetPoint + "实际目标点：" + validRealPos);
            }
            else
            {
                LogicLog.LogError($"传送失败，目标点：{targetPoint}，{(errorCode == 1 ? "目标点附近没有找到可行走区域" : (errorCode == 2 ? "移动阻挡Agent失败" : "Unknown"))}");
            }
            return success;
        }

        /// <summary>
        /// 更新位置，执行和位置有关的逻辑
        /// 注意网格寻路的计算应该在该方法调用之前
        /// </summary>
        /// <param name="position"></param>
        /// <param name="speedRatio">用于给视图层同步，代表相对于默认速度的比率</param>
        /// <param name="needSync">是否将结果同步给客户端</param>
        /// <param name="dirType"></param>
        /// <returns></returns>
        public virtual bool UpdateMove(Vector3Logic position, float speedRatio, bool needSync = true, EntityMoveDirType dirType = EntityMoveDirType.KeepVertical)
        {
            if (this.position == position)
            {
                return false;
            }
            switch (dirType)
            {
                case EntityMoveDirType.KeepVertical:
                    Vector3Logic dir = position - this.position;
                    dir.y = 0;
                    dirUnnormalized = dir;
                    break;
                case EntityMoveDirType.Free:
                    dirUnnormalized = position - this.position;
                    break;
                default:
                    break;
            }
            this.position = position;
            return true;
        }

        /// <summary>
        /// 被其他实体占用，通常不能再处理其他逻辑（但特定占用状态可能同时发生）
        /// </summary>
        /// <param name="status">占用类型</param>
        /// <param name="param">占用状态对应的参数值</param>
        /// <param name="interactingEntity">正在与之交互的实体</param>
        /// <param name="pauseOtherActionIfCan">当该状态的执行可以暂停其他动作时，是否需要暂停</param>
        public void OccupiedBy(EntityOccupationStatus status, int param, object objParam, BaseEntity interactingEntity, bool pauseOtherActionIfCan)
        {
            _occupationStatus = _occupationStatus ?? new();
            _occupationStatus[status] = param;
            if (objParam != null)
            {
                _occupationStatusObj = _occupationStatusObj ?? new();
                _occupationStatusObj[status] = objParam;
            }
            _interactingEntityMap = _interactingEntityMap ?? new Dictionary<EntityOccupationStatus, BaseEntity>();
            _interactingEntityMap[status] = interactingEntity;

            if (pauseOtherActionIfCan && IsSoloOccupationStatus(status))
            {
                PauseOrResumeInterruptibleActions(true);
            }
        }

        public void OccupiedBy(EntityOccupationStatus status, object objParam, BaseEntity interactingEntity, bool pauseOtherActionIfCan)
        {
            OccupiedBy(status, 0, objParam, interactingEntity, true);
        }

        public void OccupiedBy(EntityOccupationStatus status, int param, BaseEntity interactingEntity, bool pauseOtherActionIfCan)
        {
            OccupiedBy(status, param, null, interactingEntity, true);
        }

        public void OccupiedBy(EntityOccupationStatus status, object objParam, BaseEntity interactingEntity)
        {
            OccupiedBy(status, 0, objParam, interactingEntity, true);
        }

        public void OccupiedBy(EntityOccupationStatus status, int param, BaseEntity interactingEntity)
        {
            OccupiedBy(status, param, null, interactingEntity, true);
        }

        public void OccupiedBy(EntityOccupationStatus status, object objParam)
        {
            OccupiedBy(status, 0, objParam, null, true);
        }

        public void OccupiedBy(EntityOccupationStatus status, int param)
        {
            OccupiedBy(status, param, null, null, true);
        }

        public void OccupiedBy(EntityOccupationStatus status)
        {
            OccupiedBy(status, 0, null, null, true);
        }

        /// <summary>
        /// 是否在动作执行上具有排他性的占用状态
        /// 如果是，在该占用状态下，要停止其他行为
        /// </summary>
        /// <param name="status"></param>
        /// <returns></returns>
        private bool IsSoloOccupationStatus(EntityOccupationStatus status)
        {
            return status == EntityOccupationStatus.SpeechBubble;
        }

        private void PauseOrResumeInterruptibleActions(bool isPause)
        {
            List<IInterruptibleComponent> list = ListPool<IInterruptibleComponent>.Get();
            {
                GetInterruptibleComponents(list);
                for (int i = 0; i < list.Count; i++)
                {
                    if (isPause)
                    {
                        list[i].Pause();
                    }
                    else
                    {
                        list[i].Resume();
                    }
                }
                ListPool<IInterruptibleComponent>.Put(list);
            }
        }

        /// <summary>
        /// 释放指定类型的占用状态
        /// </summary>
        /// <param name="status"></param>
        public void ReleaseOccupation(EntityOccupationStatus status)
        {
            if (_occupationStatus == null)
                return;
            _occupationStatus.Remove(status);
            _occupationStatusObj?.Remove(status);
            _interactingEntityMap.Remove(status);

            if (IsSoloOccupationStatus(status))
            {
                PauseOrResumeInterruptibleActions(false);
            }
        }

        /// <summary>
        /// 获取占用状态，如果返回true表示还正被其他实体占用，不能处理新的逻辑（特定占用状态之间可能可以同时发生）
        /// </summary>
        /// <param name="status">占用状态类型</param>
        /// <param name="value">占用状态对应的参数值</param>
        /// <returns>是否正处于指定类型的占用状态</returns>
        public bool TryGetOccupation(EntityOccupationStatus status, out int value)
        {
            if (!isOccupied)
            {
                value = 0;
                return false;
            }
            return _occupationStatus.TryGetValue(status, out value);
        }

        public bool TryGetOccupation(EntityOccupationStatus status, out object value)
        {
            if (!isOccupied)
            {
                value = null;
                return false;
            }
            return _occupationStatusObj.TryGetValue(status, out value);
        }

        /// <summary>
        /// 是否在执行占用状态
        /// </summary>
        /// <param name="status"></param>
        /// <returns></returns>
        public bool IsInOccupation(EntityOccupationStatus status)
        {
            if (!isOccupied)
            {
                return false;
            }
            return _occupationStatus.ContainsKey(status);
        }

        public BaseEntity GetInteractingEntity(EntityOccupationStatus status)
        {
            if (_interactingEntityMap == null)
                return null;
            if (_interactingEntityMap.TryGetValue(status, out var entity))
            {
                return entity;
            }
            return null;
        }

        public BaseEntity GetAnyInteractingEntity()
        {
            if (_interactingEntityMap == null)
                return null;
            foreach (var kv in _interactingEntityMap)
            {
                return kv.Value;
            }
            return null;
        }

        public bool IsInteractEntity(LevelEntity entity)
        {
            if (_interactingEntityMap == null)
                return false;
            foreach (var kv in _interactingEntityMap)
            {
                if (kv.Value == entity)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 清理占用状态，具体原理参考OccupiedBy方法
        /// </summary>
        /// <param name="mutually">是否同时清理正在交互实体的占用状态</param>
        public void ClearOccupation(bool mutually)
        {
            if (!isOccupied)
                return;
            if (mutually)
            {
                foreach (var kv in _interactingEntityMap)
                {
                    kv.Value.ReleaseOccupation(kv.Key);
                }
            }
            _occupationStatus.Clear();
            _occupationStatusObj?.Clear();
            _interactingEntityMap.Clear();
        }

        /// <summary>
        /// 结束占用动作，和ClearOccupation不同的是，该方法会触发占用结束的触发器
        /// </summary>
        /// <param name="player"></param>
        public virtual void EndOccupationAction(LevelPlayer player, EntityOccupationStatus status)
        {
            ReleaseOccupation(status);
        }

        public void ReleaseComponents()
        {
            foreach (var kv in _components)
            {
                ClassPool.PutAutoType(kv.Value);
            }
            _components.Clear();
            //对常用缓存做特殊处理
            _navigator = null;
        }

        public void AddDynamicProperty(IEntityDynamicProperty property)
        {
            _dynamicProps = _dynamicProps ?? new Dictionary<EntityDynamicPropertyType, IEntityDynamicProperty>();
            _dynamicProps[property.type] = property;
        }

        public IEntityDynamicProperty GetDynamicProperty(EntityDynamicPropertyType type)
        {
            if (_dynamicProps == null)
            {
                return null;
            }
            if (_dynamicProps.TryGetValue(type, out var prop))
            {
                return prop;
            }
            return null;
        }

        public bool HasDynamicProperty(EntityDynamicPropertyType type)
        {
            if (_dynamicProps == null)
            {
                return false;
            }
            return _dynamicProps.ContainsKey(type);
        }

        public T GetOrAddDynProperty<T>(EntityDynamicPropertyType type) where T : class, IEntityDynamicProperty, new()
        {
            if (_dynamicProps != null && _dynamicProps.TryGetValue(type, out var iProp))
            {
                return iProp as T;
            }
            T prop = new T();
            AddDynamicProperty(prop);
            return prop;
        }

        /// <summary>
        /// 编辑器模式专用debug方法，不以GET打头命名是为了不干扰正常代码提示
        /// </summary>
        /// <returns></returns>
        public string DebugOccupationLog()
        {
#if UNITY_EDITOR
            if (!isOccupied)
            {
                return string.Empty;
            }
            StringBuilder sb = new StringBuilder();
            foreach (var kv in _occupationStatus)
            {
                sb.Append(kv.Key.ToString());
            }
            return sb.ToString();
#else
            return "Not support on mobile phone or server.";
#endif
        }

        public override void OnReset()
        {
            base.OnReset();
            ReleaseComponents();
            _tempComponents.Clear();
            _dynamicProps?.Clear();
            _dynamicProps = null;
            id = 0;
            position = default;
            isActive = false;
            dirUnnormalized = default;
            ObstacleId = 0;
            defaultMoveSpeed = 0;
            quadTreePos = default;
            behaviourName = null;
            stateMachineName = null;
            _region = null;
            isRemoved = false;
            _interactingEntityMap = null;
            _occupationStatus = null;
        }
    }
}
